using System;
using Microsoft.CSharp;
using System.CodeDom.Compiler;
using Microsoft.Xna.Framework;

namespace SolarWinds.Animations
{
    public class ExpressionAnimation : Animation
    {
        private string mExpression;
        
        public string Expression
        {
            get { return mExpression; }
            set 
            { 
                mExpression = value;

                mInited = Init();
            }
        }

        bool mInited = false;

        MathExpressionBase exprBase = null;

        private bool Init()
        {
            CSharpCodeProvider cp = new CSharpCodeProvider();
#pragma warning disable 612,618
            ICodeCompiler ic = cp.CreateCompiler();
#pragma warning restore 612,618

            CompilerParameters cpar = new CompilerParameters();
            cpar.GenerateInMemory = true;
            cpar.GenerateExecutable = false;
            cpar.ReferencedAssemblies.Add("system.dll");
            cpar.ReferencedAssemblies.Add("DeepSpace.exe");
            
            string src = "using System;" +
                         "class myclass:DeepSpace.Animation.MathExpressionBase" +
                         "{" +
                         "public myclass(){}" +
                         "public override float eval(float t)" +
                         "{" +
                         "return (float)(" + mExpression + ");" +
                         "}" +
                         "}";
            
            CompilerResults cr = ic.CompileAssemblyFromSource(cpar, src);

            foreach (CompilerError ce in cr.Errors)
            {
                Console.Out.WriteLine(ce.ErrorText);
            }

            if (cr.Errors.Count == 0 && cr.CompiledAssembly != null)
            {
                Type ObjType = cr.CompiledAssembly.GetType("myclass");
                try
                {
                    if (ObjType != null)
                    {
                        exprBase = (MathExpressionBase)Activator.CreateInstance(ObjType);
                    }
                }
                catch (Exception)
                {
                    //  MessageBox.Show(ex.Message);
                }
                return true;
            }
            return false;
        }
        
        public ExpressionAnimation(Object controlled, 
                                   string propertyName, string channelName)
            :base(controlled, propertyName, channelName)
        {
        }

        public ExpressionAnimation(Object controlled, string propertyName)
            : base(controlled, propertyName)
        {
        }

        public override void Update(GameTime gameTime)
        {
            float t = (float)((gameTime.TotalGameTime - BeginTime).TotalMilliseconds /
                              Duration.TotalMilliseconds);

            SetChannel(eval(t));
        }

        public float eval(float t)
        {
            float val = 0.0f;
            if (exprBase != null)
            {
                val = exprBase.eval(t);
            }
            return val;
        }
    }
}